
function AnimationSequence() {
  this.animations = [];
  this.index = 0;
}

AnimationSequence.prototype.addAnimation = function(animation) {
  this.animations.push(animation);
};

AnimationSequence.prototype.animate = function() {
  for (var i = 0; i < this.animations.length - 1; i++) {
    var currAnimation = this.animations[i];
    var nextAnimation = this.animations[i + 1];
    currAnimation.callback = nextAnimation.animate.bind(nextAnimation);
  }
  this.animations[0].animate;
};

/*
  Constructor

  @param String elementId The id of the element to fade.
  @param Number endOpacity The desired final opacity for the element (in %).
  @param Number speed How long the animation should take, in milliseconds.
  @param Number step The number of intermediate opacities to use.
  @param Function opt_callback The function to call when done animating.
*/
function FadeAnimation(elementId, endOpacity, length, steps, opt_callback) {
  this.elementId = elementId;
  this.endOpacity = endOpacity;
  this.length = length;
  this.steps = steps;
  this.callback = opt_callback;

  this.currOpacity = util.getOpacity($(this.elementId));
  this.opacityStep = Math.abs(this.endOpacity - this.currOpacity) / this.steps;
  this.timeStep = this.length / this.steps;
}

/*
  This method gets called repeatedly on a timer to incrementally adjust the
  opacity of the specified element.
*/
FadeAnimation.prototype.animate = function () {
  var element = $(this.elementId);
  var deltaOpacity = Math.abs(this.endOpacity - this.currOpacity);

  /* If the delta is less than one step, go straight to the endOpacity */
  if (Math.abs(deltaOpacity) <= this.opacityStep) {
    util.setOpacity(element, this.endOpacity);
    if (this.callback) {
      this.callback();
    }
    return;
  }

  /* Move the opacity a step closer to the end opacity */
  if (this.currOpacity > this.endOpacity) {
    this.currOpacity -= this.opacityStep;
  } else {
    this.currOpacity += this.opacityStep;
  }

  /* Setup the next iteration */
  window.setTimeout(this.animate.bind(this), this.timeStep);

  /* Make the opacity adjustment for this iteration */ 
  util.setOpacity(element, this.currOpacity);
};























// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// Deprecated code still used by the reservations system.
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------


// Animation Sequence Object
function animationSequence () {
  this.animations = new Array();
  this.index = 0;
}
animationSequence.prototype.add = function (animationObj) {
  this.animations.push(animationObj);
}
animationSequence.prototype.animate = function () {
  for (var i = 0; i < this.animations.length - 1; i++) {
    this.animations[i].whenDoneCall = Delegate.create(this.animations[i+1],this.animations[i+1].animate);
  }
  this.animations[0].animate();
}

// Animation Object
function animation(id, mode, par1, par2, par3, par4) {
  this.objId = id;
  this.mode = mode;
  this.timeSpan = 0;
  if (this.mode == 'fade') {
    this.finalOpacity = par1;
    this.speed = par2;
    this.step = par3;
  }
  else if ((this.mode == 'move') || (this.mode == 'resize')) {
    this.desiredX = par1;
    this.desiredY = par2;
  }
  this.speed = 20;
  if (this.mode == 'fade') { this.step = 0.10; }
  else { this.step = 20; }

  this.whenDoneCall = function () {}
}

animation.prototype.animate = function () {
  if (this.mode == 'move') {
    this.move();
  } else if (this.mode == 'resize') {
    this.resize();
  } else if (this.mode == 'fade') {
    this.fade();
  }
};

animation.prototype.move = function () {
  var targetObj = document.getElementById(this.objId);
  var pos = util.findPos(targetObj);

  var xTravelDistance = this.desiredX - pos[0];
  var yTravelDistance = this.desiredY - pos[1] ;

  if (this.timeSpan > 0)  {
    var iterations = this.timeSpan / this.speed;
    var totalDistance = Math.sqrt(Math.pow(xTravelDistance,2) + Math.pow(yTravelDistance,2));
    this.step = totalDistance / iterations;
    this.timeSpan = 0;
  }

  var angle = Math.atan(yTravelDistance/xTravelDistance);
  var yStep = this.step * Math.sin(angle);
  var xStep = this.step * Math.cos(angle);

  // If we're within one step from finishing, finish.
  if (Math.abs(xTravelDistance) <= xStep) {
    targetObj.style.left = this.desiredX + 'px';
    targetObj.style.top = this.desiredY + 'px';
    this.whenDoneCall();
    return;
  }

  // If we're not there yet, keep going
  if (xTravelDistance != 0) {
    var newLeft = pos[0] + xStep;
    targetObj.style.left = newLeft + 'px';
    var newTop = pos[1] + yStep;
    targetObj.style.top = newTop + 'px';
    setTimeout(Delegate.create(this, this.move),this.speed);
  }
}

animation.prototype.resize = function () {
  var targetObj = document.getElementById(this.objId);
  var xStep = this.step;
  var yStep;

  var currWidth = targetObj.offsetWidth;
  var currHeight = targetObj.offsetHeight;

  var xTravelDistance = this.desiredX - currWidth;
  var yTravelDistance = this.desiredY - currHeight;

  yStep = xStep * yTravelDistance / xTravelDistance;

  if (Math.abs(xTravelDistance) <= xStep) {
    targetObj.style.width = this.desiredX + 'px';
    targetObj.style.height = this.desiredY + 'px';
    this.whenDoneCall();
    return;
  }

  if (xTravelDistance < 0) xStep *= -1;
  if (yTravelDistance < 0) yStep *= -1;

  if (xTravelDistance != 0) {
    var newLeft = currWidth + xStep;
    targetObj.style.width = newLeft + 'px';
    var newTop = currHeight + yStep;
    targetObj.style.height = newTop + 'px';
    setTimeout(Delegate.create(this, this.resize),this.speed);
  }
}

animation.prototype.fade = function () {
  var targetObj = document.getElementById(this.objId);
  var currOpacity = this.getOpacity(targetObj);

  if (this.timeSpan > 0)  {
    var iterations = this.timeSpan / this.speed;
    var totalChange = Math.abs(this.finalOpacity - currOpacity);
    this.step = totalChange / iterations;
    this.timeSpan = 0;
  }

  if (Math.abs(this.finalOpacity - currOpacity) <= this.step) {
    this.setOpacity(targetObj,this.finalOpacity);
    this.whenDoneCall();
    return;
  }

  if (currOpacity > this.finalOpacity) currOpacity -= this.step;
  else currOpacity += this.step;

  if (currOpacity != this.finalOpacity) {
    setTimeout(Delegate.create(this, this.fade),this.speed);
  }
  this.setOpacity(targetObj,currOpacity);
}

animation.prototype.setOpacity = function (element,value) {
  if (element.filters) {
    try {
      element.filters['alpha'].opacity = value * 100;
    } catch (e) { }
  } else if (element.style.opacity) {
    element.style.opacity = '' + value;
  }
}

animation.prototype.getOpacity = function (element) {
  if (element.filters) return element.filters['alpha'].opacity / 100;
  if (element.style.opacity) return parseFloat(element.style.opacity);
  return null;
}
